package krypto.exercise;

import java.math.BigInteger;

public class EuclidBigInteger {

	public static void main(String[] args) throws Exception {
		BigInteger a,b,n;

		a = BigInteger.valueOf(187);
		b = BigInteger.valueOf(144);
		//		a = new BigInteger("187");
		//		b = new BigInteger("144");			
		n = new BigInteger("123456789022");
		a = new BigInteger("12345678901");
		b = new BigInteger("1234567890");
		//		a = new BigInteger("100000000000000000000000000000000000000022000000555500000888800000000000050000000001");
		//		b = new BigInteger("100000044444444000999999999999999999999999999999999999999999000888888888888888000");
		n = new BigInteger("15");
		a = new BigInteger("180");
		b = new BigInteger("7");
//		a = new BigInteger("160");
//		b = new BigInteger("3");
		//a = 12345678901;
		//b = 1234567890;

		//System.out.println("Slow version input=" + a + "," + b + " gcd=" + EuclidStandard(a,b));

		//System.out.println("Fast version input=" + a + "," + b + " gcd=" + EuclidFaster(a,b));

				EEResultBigInteger eEResultBigInteger = EEuclid.calc(a,b);
				if (eEResultBigInteger != null) {
					System.out.println("Extendend version input=" + a + "," + b + " gcd=" + eEResultBigInteger.L + " x,y=" + eEResultBigInteger.x + "," + eEResultBigInteger.y );
				} else {
					System.out.println("Fejl!");
				}

		//EEResultBigInteger eEResultBigInteger;
		a = new BigInteger("180");
		b = new BigInteger("2");

		for (int i=1; i<a.intValue(); i++) {
//			eEResultBigInteger = EuclidExtended(a,b);
			eEResultBigInteger = EEuclid.calc(a,b);
			if (eEResultBigInteger.L.equals(BigInteger.valueOf(1))) {
				System.out.println(b);
			}
			b = b.add(BigInteger.valueOf(1));
		}





		//		BigInteger mIResult = EEMultiplicativeInverse(a,n);
		//		System.out.println("Mulitplicative Inverse input=" + a + "," + n + " Result=" + mIResult);
		//		//Test
		//  		BigInteger abmodn = (a.multiply(mIResult)).mod(n);
		//  		if ( abmodn.compareTo(BigInteger.valueOf(1)) != 0) {
		//  			System.out.println("Fejl. abmodn skal altid være 1, men er=" + abmodn);
		//  		} else {
		//  			System.out.println("Succes. abmodn skal altid være 1, og er=" + abmodn);
		//  		}
		//  			





	}

	private static BigInteger EEMultiplicativeInverse (BigInteger a, BigInteger n) throws Exception {
		BigInteger result = null;

		//Check that a < n
		//This method returns -1, 0 or 1 as this BigInteger is numerically less than, equal to, or greater than val.
		if ((a.compareTo(n)) >= 0) {
			System.out.println("a should be lower than n");
			return null;
		}

		//Check that gcd(a,n) = 1
		EEResultBigInteger eEResultBigInteger = EEuclid.calc(n,a);
		if (eEResultBigInteger == null) {
			System.out.println("Fejl!");
		} else {

			if ((eEResultBigInteger.L.compareTo(BigInteger.valueOf(1) )) == 0) {
				result = eEResultBigInteger.y.mod(n);
			} else {
				System.out.println("gcd er ikke lig 1, men =" + eEResultBigInteger.L);
			}
		}

		return result;
	}

//	private static EEResultBigInteger EuclidExtended (BigInteger a, BigInteger b) {
//		//		LocalTimer lt = new LocalTimer();
//		EEResultBigInteger result = new EEResultBigInteger();
//
//		//This method returns -1, 0 or 1 as this BigInteger is numerically less than, equal to, or greater than val.
//		if ((a.compareTo(b)) < 0) {
//			System.out.println("a should be bigger or equal to b");
//			return null;
//		}
//
//		BigInteger L = a;
//		BigInteger R = b;
//		BigInteger x = BigInteger.valueOf(1);
//		BigInteger y = BigInteger.valueOf(0);
//		BigInteger X = BigInteger.valueOf(0);
//		BigInteger Y = BigInteger.valueOf(1);
//
//		BigInteger q;
//		BigInteger t;
//		BigInteger u;
//		BigInteger v;
//
//		do {
//			q = L.divide(R);
//			t = R;
//			R = L.mod(R);
//			L = t;
//			u = X;
//			v = Y;
//			X = x.subtract(q.multiply(X));
//			Y = y.subtract(q.multiply(Y));
//			x = u;
//			y = v;
//
//		} while ( R.compareTo(BigInteger.valueOf(0)) != 0);
//
//		result.L = L;
//		result.x = x;
//		result.y = y;
//
//		//		lt.stop();		
//		return result;
//	}


	private static BigInteger EuclidFaster (BigInteger a, BigInteger b) {
		LocalTimer lt = new LocalTimer();
		BigInteger t;

		//if (b > a) {
		if (b.compareTo(a) > 0) {
			t = a;
			a = b;
			b = t;
		}

		do {
			t = b;
			b = a.mod(b);
			a = t;

			// while (b > 0)
		} while (b.compareTo(BigInteger.valueOf(0)) > 0);


		lt.stop();
		return a;
	}

	@SuppressWarnings("unused")
	private static BigInteger EuclidStandard (BigInteger a, BigInteger b) {
		LocalTimer lt = new LocalTimer();
		BigInteger t;

		do {
			if (b.compareTo(a) > 0) {
				t = a;
				a = b;
				b = t;
			}
			a = a.subtract(b);
			// while (b > 0)
		} while (b.compareTo(BigInteger.valueOf(0)) > 0);


		lt.stop();
		return a;
	}
}

//class EEResultBigInteger {
//	BigInteger L;
//	BigInteger x;
//	BigInteger y;
//}

//class LocalTimer {
//	private long stopwatchStart, stopwatchStop;
//
//	LocalTimer() {
//		stopwatchStart = System.currentTimeMillis();
//	}
//
//	public void stop () { 
//		stopwatchStop = System.currentTimeMillis();
//		System.out.println("Operation lasted " + (stopwatchStop - stopwatchStart) + " milliseconds.");
//	}
//}



